package com.smsc.headend.task.engine.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Preconditions;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.smsc.headend.common.enums.Dictionary;
import com.smsc.headend.common.utils.CosemUtils;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.common.AppName;
import com.smsc.headend.module.common.entity.ScalerUnit;
import com.smsc.headend.module.data.entity.ScheduleReadingEntity;
import com.smsc.headend.task.engine.manager.DdsFilterMdmDataManager;
import com.smsc.headend.task.engine.mapper.RdMeterReadsLpMapper;
import com.smsc.headend.task.engine.service.DataConvertService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.list.UnmodifiableList;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DataConvertServiceImpl implements DataConvertService {

    @Autowired
    FeignAssetManagementService feignAssetManagementService;

    @Autowired
    DdsFilterMdmDataManager ddsFilterMdmDataManager;

    @Autowired
    RdMeterReadsLpMapper rdMeterReadsLpMapper;

    @Autowired
    AssetService assetService;

    List<Integer> reverseCoverRateUnitId = UnmodifiableList.unmodifiableList(Arrays.asList(27, 28, 29, 30, 31, 32));

    LoadingCache<Long, String> subDataItemDescCache = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).build(new CacheLoader<Long, String>() {
        @Override
        public String load(Long subDataItemId) throws Exception {
            return rdMeterReadsLpMapper.getSubDataItemDescSubDataItemId(subDataItemId);
        }
    });


    @Override
    public Map<String, String> getSubDataItemIdName(ArrayList<Long> dataItemIds, String lang, Boolean unitAppend, String moduleName) {
        log.info("get dataItem Name in {}", lang);
        Map<String, String> resultMap = new HashMap<>();
        Preconditions.checkArgument((unitAppend && moduleName != null) || !unitAppend);
        dataItemIds.stream().forEach(id -> {
            String dataItemKey = Dictionary.DATA_ITEM.getKeyPrefix() + id;
            dataItemKey = dataItemKey.substring(0, dataItemKey.length() - 3);
            String value = feignAssetManagementService.i18n(dataItemKey, lang);
            if (unitAppend) {
                String subDataDesc = null;
                try {
                    subDataDesc = subDataItemDescCache.get(id);
                } catch (ExecutionException e) {
                    log.info("getSubDataItemId false:{}", id);
                }
                if (StringUtils.isEmpty(subDataDesc)) {
                    return;
                }
                value = value + "-" + subDataDesc;
                String key = id + ":" + AppName.GUI.toString();
                String unitName = ddsFilterMdmDataManager.getAppConfigUnitName(key);
                if (StrUtil.isNotEmpty(unitName) && !DdsFilterMdmDataManager.NULL_STR.equalsIgnoreCase(unitName)) {
                    value = value + "(" + unitName + ")";
                }
            }
            resultMap.put(Convert.toStr(id), value);
        });
        return resultMap;
    }

    @Override
    public List<ScheduleReadingEntity> convertCTVT(List<ScheduleReadingEntity> dataList) {
        List<String> calculateRatioSubDataList = rdMeterReadsLpMapper.getCalculateRatioSubDataList();
        for (ScheduleReadingEntity scheduleReadingEntity : dataList) {
            Long meterId = (Long) scheduleReadingEntity.get("meterId");
            Meter meter = assetService.getMeterById(meterId);

            if (StringUtils.isEmpty(meter.getCt()) || StringUtils.isEmpty(meter.getVt())) {
                continue;
            }
            if (!NumberUtil.isNumber(meter.getCt()) || !NumberUtil.isNumber(meter.getVt())) {
                continue;
            }
            Double rate = Convert.toDouble(meter.getCt()) * Convert.toDouble(meter.getVt());
            List<String> dataItemIdsInScheduleData = (List<String>) scheduleReadingEntity.keySet().stream().filter(s -> {
                String keyStr = Convert.toStr(s);
                return keyStr.startsWith("1");
            }).collect(Collectors.toList());

            for (String dataItemIdsInScheduleDatum : dataItemIdsInScheduleData) {
                boolean contains = calculateRatioSubDataList.contains(dataItemIdsInScheduleDatum);
                if (contains) {
                    try {
                        scheduleReadingEntity.put(dataItemIdsInScheduleDatum, StrUtil.toString(Convert.toDouble(scheduleReadingEntity.get(dataItemIdsInScheduleDatum)) * rate));
                    } catch (Exception e) {
                        log.error("convertCTVTError, id:{},value:{}, rate:{}", dataItemIdsInScheduleDatum, scheduleReadingEntity.get(dataItemIdsInScheduleDatum), rate, e);
                    }
                }
            }
        }
        return dataList;
    }

    @Override
    public String getI18NStr(String key, String locale) {
        return feignAssetManagementService.i18n(key, locale);
    }

    @Override
    public String getGUIValue(String value, Long modelId, Long subDataItemId) {
//        //Start: MDM要求所有时间格式以时间戳的形式返回.此处特殊处理
//        String timestamp = null;
//        if (StringUtils.isEmpty(value)) {
//            return null;
//        }
//        if (!StringUtils.isEmpty(value) && value.contains("-") && value.contains(":")) {
//            try {
//                timestamp = String.valueOf(DateUtils.parseDate(value, new String[]{"yyyy-MM-dd HH:mm:ss"}).getTime() / 1000);
//            } catch (Exception e) {
//            }
//        }
//        if (!StringUtils.isEmpty(timestamp)) {
//            return timestamp;
//        }
//        //End.
        if (!NumberUtil.isNumber(value)) {
            return value;
        }
        BigDecimal val = new BigDecimal(value);
        String key = modelId + ":" + subDataItemId + ":" + AppName.GUI.toString();
        ScalerUnit scalerUnit = ddsFilterMdmDataManager.getScaleUnit(key);
        if (scalerUnit == null) {
            //获取单位失败, 返回原值带 ？
            return value;
        }

        String coverRate = ddsFilterMdmDataManager.getCoverRate(key);
        if (coverRate == null) {
            //获取量纲失败，不传输到mdm
            return null;
        }

        if ("ascii".equalsIgnoreCase(coverRate)) {
            if (CosemUtils.isAsciiHexStr(value)) {
                value = HexUtil.decodeHexStr(value);
                return value;
            }
        }

        if (scalerUnit.getSubDataItemId() == -1L) {
            //获取到单位为空， 返回原值
            return value;
        }

        val = val.multiply(new BigDecimal(Math.pow(10, scalerUnit.getScaler()))).setScale((int) Math.abs(3), BigDecimal.ROUND_HALF_UP);

        if (!DdsFilterMdmDataManager.NULL_STR.equalsIgnoreCase(coverRate) && !"ascii".equalsIgnoreCase(coverRate) && NumberUtil.isNumber(coverRate)) {
            if (reverseCoverRateUnitId.contains(scalerUnit.getUnit())) {
                Double rate = 1 / Double.parseDouble(coverRate);
                coverRate = rate.toString();
            }
            val = val.multiply(new BigDecimal(coverRate)).setScale((int) Math.abs(3), BigDecimal.ROUND_HALF_UP);
        }
        return val.toString();
    }


}
